package com.quanquan.user.service.autoCompute.service;

import com.quanquan.user.entity.User;
import com.quanquan.user.service.autoCompute.dto.OptionUnity;
import com.quanquan.user.service.autoCompute.dto.TableField;
import com.quanquan.user.service.autoCompute.annotion.Options;
import com.quanquan.user.service.autoCompute.enums.OptionType;
import lombok.extern.log4j.Log4j2;
import org.hibernate.SessionFactory;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.hibernate.persister.walking.spi.AttributeDefinition;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import utils.StringUtil;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 获取表的字段名、字段类型
 */
@Log4j2
@Service
public class GeneralService {

    @PersistenceContext
    private EntityManager entityManager;

    public List<TableField> getTableFields(Class<?> clazz) {
        if (null == clazz) return new ArrayList<>();
        EntityManagerFactory entityManagerFactory = entityManager.getEntityManagerFactory();
        SessionFactoryImpl sessionFactory = (SessionFactoryImpl) entityManagerFactory.unwrap(SessionFactory.class);
        SingleTableEntityPersister persister = (SingleTableEntityPersister) sessionFactory.locateEntityPersister(clazz);
        String tableName = persister.getTableName();    //表名称
        Iterable<AttributeDefinition> attributes = persister.getAttributes();
        List<TableField> list = new LinkedList<>();
        attributes.forEach(attr -> {
            //在entity中的属性名称
            String propertyName = attr.getName();
            //对应数据库表中的字段名
            String[] columnName = persister.getPropertyColumnNames(propertyName);
            Field field = null;
            try {
                field = clazz.getDeclaredField(propertyName);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
            Options optionsAnnotation = field.getAnnotation(Options.class);
            if (optionsAnnotation != null) {
                String fieldName = optionsAnnotation.fieldName();
                PropertyDescriptor targetPd = BeanUtils.getPropertyDescriptor(User.class, propertyName);
                String type = targetPd != null ? targetPd.getPropertyType().getSimpleName() : "";
                List<OptionUnity> optionUnityList = new LinkedList<>();
                String[] options = optionsAnnotation.value();
                String[] alias = optionsAnnotation.alias();
                if (alias.length > 0) {
                    if (options.length != alias.length) {
                        log.warn("[{}] 别名与值 数量不一致", fieldName);
                        return;
                    }
                    for (int i = 0; i < options.length; i++) {
                        OptionUnity unity = new OptionUnity();
                        unity.setAlias(alias[i]);
                        unity.setValue(options[i]);
                        optionUnityList.add(unity);
                    }
                } else {
                    for (int i = 0; i < options.length; i++) {
                        OptionUnity unity = new OptionUnity();
                        unity.setValue(options[i]);
                        optionUnityList.add(unity);
                    }
                }
                OptionType optionType = optionsAnnotation.type();
                String fieldType = optionsAnnotation.fieldType();
                if (StringUtil.isNotEmpty(fieldType)) {
                    type = fieldType;
                }
                TableField tableField = new TableField(tableName, fieldName, columnName[0], type, optionType, false, 0, optionUnityList);
                list.add(tableField);
            }
        });
        return list;
    }

}
